import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author fsyj
 */
public class FileByteConsumer extends Thread {

    public static final String THREAD_PREFIX = "update-thread:";


    public static final int U_1_BYTE_JUDGE = 0b10000000;
    public static final int U_2_BYTE_JUDGE = 0b11100000;
    public static final int U_3_BYTE_JUDGE = 0b11110000;
    public static final int U_4_BYTE_JUDGE = 0b11111000;

    public static final int U_1_BYTE_EQU = 0b00000000;
    public static final int U_2_BYTE_EQU = 0b11000000;
    public static final int U_3_BYTE_EQU = 0b11100000;
    public static final int U_4_BYTE_EQU = 0b11110000;


    private ArrayBlockingQueue<IndexedData> queue;

    private File outputFile;

    public FileByteConsumer(ArrayBlockingQueue<IndexedData> queue, File outputFile) {
        this.queue = queue;
        this.outputFile = outputFile;
    }

    @Override
    public void run() {
        // 设置偏移量，如一个字符的utf8编码存储在两个数组的首尾，需要进行便偏移，更具体的说，偏移量代表一个UTF-8字符的字节长度
        int offset = 0;
        int index = 0;
        // 输出数组结束位置，遇到0就截止
        int endIndex = 0;
        RandomAccessFile ras = null;
        try {
            ras = new RandomAccessFile(outputFile, "rw");
            while (true) {
                IndexedData data = queue.take();
                if (data.getIndex() == -1) {
                    // 终结标识，表示生产者已经生产完成，可以退出消费
                    break;
                }
                byte[] content = data.getData();
                // 设置起始位置
                index = offset;
                // 设置初始end
                endIndex = content.length;
                for (; index < content.length; index += offset) {
                    // 如果当前指向的字节为0了，就终止
                    if (content[index] == 0) {
                        endIndex = index;
                        break;
                    }
                    // 遍历每一个UTF-8字符，如果满足条件，就替换
                    // 获取字节数组指定 index 位置的UTF-8编码长度
                    offset = getU8Length(content, index);
                    // 观察替代条件，替代字符都以ASCII码可以表示，所以，需要替代的字符字节长度一定为1
                    if (offset == 1) {
                        int num = content[index];
                        switch (num) {
                            case 49:
                                content[index] = 97;
                                break;
                            case 50:
                                content[index] = 98;
                                break;
                            case 51:
                                content[index] = 99;
                                break;
                            case 52:
                                content[index] = 100;
                                break;
                            default:
                                break;
                        }
                    }
                }
                // 计算下个buffer数组的起始偏移量
                offset = index - content.length;

                // 然后就是将这个buffer数组push到out流
                // 输出位置应该时当前数据包的index * buffer size
                ras.seek(data.getIndex() * FileByteProducer.BUFFER_SIZE);
                ras.write(content, 0, endIndex);
            }
        } catch (IOException | InterruptedException e) {
            // 日志记录
            e.printStackTrace();
        } finally {
            if (ras != null) {
                try {
                    ras.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private int getU8Length(byte[] buffer, int index) {
        byte num = buffer[index];
        if ((num & U_1_BYTE_JUDGE) == U_1_BYTE_EQU) {
            return 1;
        } else if ((num & U_2_BYTE_JUDGE) == U_2_BYTE_EQU) {
            return 2;
        } else if ((num & U_3_BYTE_JUDGE) == U_3_BYTE_EQU) {
            return 3;
        } else if ((num & U_4_BYTE_JUDGE) == U_4_BYTE_EQU) {
            return 4;
        } else {
            throw new IllegalArgumentException("UTF-8编码最多支持4字节编码字符");
        }
    }
}
